#include "StdAfx.h"
#include "DataCrypt.h"
#include "cryptlib.h"
#include "aes.h"
#include "des.h"
#include "modes.h"
#include "filters.h"

//#ifdef _DEBUG
//#pragma comment(lib, "cryptlibd.lib")
//#else
//#pragma comment(lib, "cryptlib.lib")
//#endif

using namespace CryptoPP;

DataCrypt::DataCrypt(void)
{
}

DataCrypt::~DataCrypt(void)
{
}

ByteBuffer DataCrypt::DES_Encrypt(const byte* key, int keyLen, const byte* data, int dateLen, int mode)
{
    ByteBuffer ret, _data;
    size_t len = (dateLen/DES::KEYLENGTH+(dateLen%DES::KEYLENGTH?1:0))*DES::KEYLENGTH;
    ret.resize(len);
    _data.resize(len);
    memcpy((void*)_data.contents(), data, dateLen);
    byte __key[32] = {0};
    memcpy(__key, key, keyLen);
    ECB_Mode<DES>::Encryption desEn;
    try
    {
        desEn.SetKey(__key, DES::KEYLENGTH);
        desEn.ProcessData((byte*)ret.contents(), _data.contents(), len);
    }
    catch(const CryptoPP::Exception& e)
    {
        assert(0);
    }
    return ret;
}

ByteBuffer DataCrypt::DES_Decrypt(const byte* key, int keyLen, const byte* data, int dateLen, int mode)
{
    ByteBuffer ret, _data;
    size_t len = (dateLen/DES::KEYLENGTH+(dateLen%DES::KEYLENGTH?1:0))*DES::KEYLENGTH;
    ret.resize(len);
    _data.resize(len);
    memcpy((void*)_data.contents(), data, dateLen);
    byte __key[32] = {0};
    memcpy(__key, key, keyLen);
    ECB_Mode<DES>::Decryption desDn;
    try
    {
        desDn.SetKey(__key, DES::KEYLENGTH);
        //desDn.ProcessBlock(data, (byte*)ret.contents());
        desDn.ProcessData((byte*)ret.contents(), _data.contents(), len);
    }
    catch(const CryptoPP::Exception& e)
    {
        ret.clear();
        assert(0);
    }

    return ret;
}

ByteBuffer DataCrypt::DES3_Encrypt(const byte* key1, const byte* key2, const byte* key3, const byte* data, int dateLen, int mode)
{
    ByteBuffer ret;
    return ret;
}

ByteBuffer DataCrypt::DES3_Dncrypt(const byte* key1, const byte* key2, const byte* key3, const byte* data, int dateLen, int mode)
{
    ByteBuffer ret;
    return ret;
}

ByteBuffer DataCrypt::AES_Encrypt(const byte* key, int keyLen, const byte* data, int dateLen)
{
    ByteBuffer ret;
    ret.resize(AES::BLOCKSIZE);
    byte aesKey[AES::DEFAULT_KEYLENGTH] = {0};
    memcpy(aesKey, key, keyLen);
    byte inBlock[AES::BLOCKSIZE] = {0};
    memcpy(inBlock, data, dateLen);
    byte xorBlock[AES::BLOCKSIZE] = {0};


    AESEncryption aesEn;
    aesEn.SetKey(aesKey, AES::DEFAULT_KEYLENGTH);
    aesEn.ProcessBlock(inBlock, (byte*)ret.contents());
    return ret;
}

ByteBuffer DataCrypt::AES_Decrypt(const byte* key, int keyLen, const byte* data, int dateLen)
{
    ByteBuffer ret;
    ret.resize(AES::BLOCKSIZE);
    byte aesKey[AES::DEFAULT_KEYLENGTH] = {0};
    memcpy(aesKey, key, keyLen);
    byte inBlock[AES::BLOCKSIZE] = {0};
    memcpy(inBlock, data, dateLen);
    AESDecryption aesDn;
    aesDn.SetKey(aesKey, AES::DEFAULT_KEYLENGTH);
    aesDn.ProcessBlock(inBlock, (byte*)ret.contents());
    return ret;
}

ByteBuffer DataCrypt::AES_EncryptEcb(const byte* key, int keyLen, string data)
{
    byte aesKey[AES::DEFAULT_KEYLENGTH] = {0};
    memcpy(aesKey, key, keyLen);
    ECB_Mode< AES >::Encryption e;
    e.SetKey(aesKey, AES::DEFAULT_KEYLENGTH);
    
    string outBuf;
    StringSource(data, true, 
        new StreamTransformationFilter(e,
            new StringSink(outBuf),
            StreamTransformationFilter::ZEROS_PADDING
        ) // StreamTransformationFilter      
    );
    ByteBuffer ret;
    ret<<outBuf;
    return ret;
}

ByteBuffer DataCrypt::AES_DecryptEcb(const byte* key, int keyLen, string data)
{
    ByteBuffer ret;
    byte aesKey[AES::DEFAULT_KEYLENGTH] = {0};
    memcpy(aesKey, key, keyLen);
    ECB_Mode< AES >::Decryption d;
    try
    {
        d.SetKey(aesKey, AES::DEFAULT_KEYLENGTH);

        string outBuf;
        // The StreamTransformationFilter removes
        //  padding as required.
        StringSource s(data, true, 
            new StreamTransformationFilter(d,
            new StringSink(outBuf),
            StreamTransformationFilter::ZEROS_PADDING
            ) // StreamTransformationFilter
            ); // StringSource
        
        ret<<outBuf;
    }
    catch(const CryptoPP::Exception& e)
    {
		e.GetErrorType();
        ret.clear();
        assert(0);
    }
    return ret;    
}